﻿using System;
using System.Collections.Generic;
using Infinity.Common.Visitor;
using Infinity.Expressions;
using Infinity.Expressions.Constant;
using Infinity.Expressions.ExpressionFactory.CallExpression;
using Infinity.Expressions.Operator;
using System.Linq;
using Infinity.Statements;
using Infinity.Statements.Block;
using Infinity.Statements.Command;
using Infinity.Statements.Condition;
using Infinity.Statements.Loop;
using System.Text;
using System.Windows.Controls;

namespace Infinity.Language.EditorDemo.Visitor
{
	public class SyntaxTreeVisitor : TreeVisitorBase<IStatement, TreeViewItem>
	{
		public SyntaxTreeVisitor()
		{
			Result = null;
		}

		public TreeViewItem Result { get; set; }

		protected TreeViewItem VisitConstraint(IStatementBase node)
		{
			if (node == null) return null;

			var treeViewItem = new TreeViewItem();

			if (node is IPreConditionStatement)
				treeViewItem = Visit((node as IPreConditionStatement).Condition);
			else if (node is IPostConditionStatement)
				treeViewItem = Visit((node as IPostConditionStatement).Condition);

			return treeViewItem;
		}

		protected TreeViewItem Visit(IExpression node)
		{
			if (node == null) return null;

			var treeViewItem = new TreeViewItem();

			if (node is IIdentifierExpression)
			{
				var expression = node as IIdentifierExpression;

				treeViewItem.Header = string.Format("Left: {0}", expression.Name);
			}
			else if (node is CallExpression)
			{

			}
			else if (node is IConstantExpression)
			{
				if (node is IIntegerNumberExpression)
				{
					var expression = node as IIntegerNumberExpression;
					treeViewItem.Header = string.Format("Number: {0}", expression.Value);
				}
				else if (node is IRealNumberExpression)
				{
					var expression = node as IRealNumberExpression;
					treeViewItem.Header = string.Format("Number: {0}", expression.Value);
				}
				else if (node is IStringExpression)
				{
					var expression = node as IStringExpression;
					treeViewItem.Header = string.Format("String: '{0}'", expression.Value);
				}
				else if (node is IBooleanExpression)
				{
					var expression = node as IBooleanExpression;
					treeViewItem.Header = string.Format("Boolean: {0}", expression.Value);
				}
			}
			else if (node is IOperatorExpression)
			{
				var expression = node as IOperatorExpression;
				if (node is IInfixOperatorExpression)
				{
					treeViewItem.Header = string.Format("Infix operator: {0}", expression.Operator.Name);
				}
				else if (node is IPrefixOperatorExpression)
				{
					treeViewItem.Header = string.Format("Prefix operator: {0}", expression.Operator.Name);
				}
				else if (node is IPostfixOperatorExpression)
				{
					treeViewItem.Header = string.Format("Postfix operator: {0}", expression.Operator.Name);
				}
				else if (node is IIterativeOperatorExpression)
				{
					treeViewItem.Header = string.Format("Iterative operator: {0}", expression.Operator.Name);
				}

				foreach (var args in expression.Arguments)
				{
					treeViewItem.Items.Add(Visit(args)					);
				}
			}

			return treeViewItem;
		}

		public override TreeViewItem Visit(IStatement node)
		{
			if (node == null) return null;

			var treeViewItem = new TreeViewItem();

			var constraintItem = new TreeViewItem() { Header = "Constraints" };

			if (node.Constraint != null)
			{
				if (node.Constraint.PreCondition != null && node.Constraint.PreCondition.Condition != null)
				{
					var preconditionItem = new TreeViewItem() { Header = "Precondition" };
					preconditionItem.Items.Add(VisitConstraint(node.Constraint.PreCondition));

					constraintItem.Items.Add(preconditionItem);
				}
				if (node.Constraint.PostCondition != null && node.Constraint.PostCondition.Condition != null)
				{
					var postconditionItem = new TreeViewItem() { Header = "Postcondition" };
					postconditionItem.Items.Add(VisitConstraint(node.Constraint.PostCondition));

					constraintItem.Items.Add(postconditionItem);
				}

				if (constraintItem.Items.Count > 0)
				{
					treeViewItem.Items.Add(constraintItem);
				}
			}

			if (node is IConditionStatement)
			{
				var condition = new TreeViewItem() { Header = "Condition" };

				if (node is IIfStatement)
				{
					var statement = node as IIfStatement;
					treeViewItem.Header = "If Statement";

					var trueBlock = new TreeViewItem() { Header = "True block" };
					trueBlock.Items.Add(Visit(statement.BodyStatement));

					var elseBlock = new TreeViewItem() { Header = "Else block" };
					elseBlock.Items.Add(Visit(statement.ElseStatement));

					var elseIfBlock = new TreeViewItem() { Header = " Else If block" };
					foreach (var s in statement.ElseIfStatements)
					{
						elseIfBlock.Items.Add(Visit(s));
					}

					condition.Items.Add(Visit(statement.Condition));

					treeViewItem.Items.Add(condition);
					treeViewItem.Items.Add(trueBlock);
					treeViewItem.Items.Add(elseIfBlock);
					treeViewItem.Items.Add(elseBlock);
				}
			}
			else if (node is ILoopStatement)
			{
				var condition = new TreeViewItem();
				condition.Header = "Condition";

				var body = new TreeViewItem();
				body.Header = "Body";

				if (node is IWhileStatement)
				{
					var statement = node as IWhileStatement;
					treeViewItem.Header = "While statement";

					condition.Items.Add(Visit(statement.Condition));
				}
				else if (node is IForeachStatement)
				{
					var statement = node as IForeachStatement;
					treeViewItem.Header = "Foreach statement";
				}
				else if (node is ILoopExitStatement)
				{
					var statement = node as ILoopExitStatement;
					treeViewItem.Header = "Loop exit statement";
				}

				body.Items.Add(Visit((node as ILoopStatement).Body));

				treeViewItem.Items.Add(condition);
				treeViewItem.Items.Add(body);
			}
			else if (node is IBlockStatement)
			{
				var statement = node as IBlockStatement;
				treeViewItem.Header = "Block statement";

				foreach (var command in statement.Commands)
				{
					treeViewItem.Items.Add(Visit(command));
				}
			}
			else if (node is ICommandStatement)
			{
				if (node is IAssignmentStatement)
				{
					var statement = node as IAssignmentStatement;
					treeViewItem.Header = "Assignment statement";

					var left = new TreeViewItem() { Header = "Left" };
					var right = new TreeViewItem() { Header = "Right" };

					left.Items.Add(Visit(statement.Left));
					right.Items.Add(Visit(statement.Value));

					treeViewItem.Items.Add(left);
					treeViewItem.Items.Add(right);
				}
			}

			return treeViewItem;
		}
	}
}
